#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   sku2_inverse_rate_calculation.py    
@Contact :   pengwei.sun@aihuishou.com
@License :   (C)Copyright aihuishou

@Modify Time      @Author       @Version    @Desciption
------------      -----------   --------    -----------
2021-06-30 14:40   pengwei.sun      1.0         None
'''
import os
import sys
sys.path.append(os.getcwd())
import pandas as pd
from src.utils.config import logger
from src.mobile.levelrate.reverse.function_utils import save_pickle_data,load_pickle_data,check_conflict_file
import pickle
import numpy as np
from src.mobile.levelrate.reverse.sku2_common_variable import  FILE_DIR
import concurrent.futures
from multiprocessing import Pool
import time

def inverse_rate_fun(group):
    try:
        group = group[1]
    except Exception as e:
        logger.info('sdsd.{}'.format(group))
    group = group.sort_values('template_rank', ascending=True)
    group.reset_index(drop=True, inplace=True)
    group = group.sort_values('template_rank', ascending=True)
    group['product_level_name_tmp']=group['product_level_name']
    group['rank_tmp'] = group['rank']
    group['saleprice_tmp'] = group['saleprice']

    size = group.shape[0]
    result_t = group
    if size<=2:
        return result_t

    for index in range(size):

        iter_size = 0
        iter_size_bi = 0
        iverse = 0
        iverse_bi = 0
        if result_t.loc[index,'level_sub'] in ['S','A','B','C','D'] and index+1<=size :
            for i in range(index+1,size,1):
                if result_t.loc[index, 'template_rank']==result_t.loc[i, 'template_rank'] :
                    continue
                iter_size+=1
                iter_size_bi+=1
                if result_t.loc[index, 'process_price']<result_t.loc[i, 'process_price'] and result_t.loc[index, 'template_rank']<result_t.loc[i, 'template_rank']:
                    iverse_bi=iverse_bi+1
                    result_t.loc[i, 'weight_cnt']=result_t.loc[i, 'weight_cnt']+1
                    result_t.loc[index, 'weight_cnt']=result_t.loc[index, 'weight_cnt']+1

                if result_t.loc[index, 'saleprice']<result_t.loc[i, 'saleprice'] and result_t.loc[index, 'template_rank']<result_t.loc[i, 'template_rank']:
                    iverse=iverse+1

            result_t.loc[index, 'iter_size']=iter_size
            result_t.loc[index, 'iter_size_bi']=iter_size_bi
            result_t.loc[index, 'iverse']=iverse
            result_t.loc[index, 'iverse_bi']=iverse_bi
            # print(' .')
        # resDf = resDf.append(result_t.copy())
    return result_t


def inverse_rate_process(result_t):
    t1 = time.time()
    result_t=result_t.loc[result_t.level_sub.isin(['S','A','B','C','D','E'])]
    resDf = pd.DataFrame(columns=result_t.columns.tolist())
    grouped = result_t.groupby('product_sku_key')

    total_gp = grouped.ngroups
    iter=0
    if total_gp>5:
        with Pool(16) as executor:
            for number, result_t in zip(grouped,
                                      executor.map(inverse_rate_fun,
                                                   grouped)):
                resDf = resDf.append(result_t.copy())
                iter += 1
                logger.info('total_gp = {} ,iter={} skuid={} is prime:'.format(total_gp, iter, number[0]))
        logger.info(' inverse_rate_process end use time @{}'.format((time.time() - t1) / 60))
    else:
        for group in grouped:
            result_t = inverse_rate_fun(group)
            resDf = resDf.append(result_t.copy())
    resDf = resDf.drop_duplicates()
    return resDf

def inverse_process_fun(group):
    group = group[1]
    group = group.sort_values('template_rank', ascending=True)
    group = group.sort_values('template_rank', ascending=True)
    group.reset_index(drop=True, inplace=True)
    size = group.shape[0]
    logger.info("sku_key={}".format(group.loc[0,'product_sku_key']))
    # result_t[['product_level_name', 'template_rank', 'reverse_cnt','weight_cnt', 'process_price', 'process_price_inverse_begin','predict_origin', 'level_rate_price','price_0_7', 'sale_num_0_7', 'iverse_bi_begin', 'thisprice','count']]
    result_t = group
    if size<=2:
        return result_t


    for index in range(1,size*2,1):

        result_t['weight_cnt']=0
        result_t=inverse_rate_process(result_t)
        max_index=result_t.loc[result_t.weight_cnt==result_t.weight_cnt.max()]
        max_index=max_index.sort_values(by=['reverse_cnt','template_rank'], ascending=[True,False])
        reverse_index=max_index.index[0]
        middle_price = result_t.loc[reverse_index, 'process_price']
        thisprice = result_t.loc[reverse_index, 'thisprice']
        if result_t.loc[reverse_index,'weight_cnt']==0:
            break
        if reverse_index==0:
            result_t.loc[reverse_index, 'reverse_cnt'] += 1
            if thisprice>0:
                if ~np.isnan(thisprice) and middle_price<thisprice:
                    result_t.loc[reverse_index, 'process_price']=thisprice
                else:
                    result_t.loc[reverse_index, 'process_price']=result_t.loc[reverse_index + 1, 'process_price']*1.02
            else:
                result_t.loc[reverse_index, 'process_price'] = result_t.loc[
                                                                   reverse_index + 1, 'process_price'] * 1.02
            continue

        if reverse_index+1<size:
            if result_t.loc[reverse_index,'reverse_cnt']>=5:
                first_index = reverse_index - 1
                for first_index in range(reverse_index - 1, 0, -1):
                    if result_t.loc[first_index, 'weight_cnt'] == 0 and result_t.loc[
                        first_index, 'template_rank'] != \
                            result_t.loc[reverse_index, 'template_rank']:
                        break
                for next_index in range(reverse_index + 1, size, 1):
                    if result_t.loc[next_index, 'weight_cnt'] == 0 and result_t.loc[next_index, 'template_rank'] != \
                            result_t.loc[reverse_index, 'template_rank'] and result_t.loc[
                        first_index, 'process_price'] > result_t.loc[next_index, 'process_price']:
                        break
                bulk_price = (result_t.loc[first_index, 'process_price'] - result_t.loc[
                    next_index, 'process_price']) / (
                                     next_index - first_index)
                # begin_after_avg_price = result_t.loc[first_index, 'process_price'] - bulk_price * (
                #             reverse_index - first_index)
                for reverse in range(first_index + 1, next_index, 1):
                    if result_t.loc[reverse, 'weight_cnt'] > 0:
                        result_t.loc[reverse, 'reverse_cnt'] += 1
                        result_t.loc[reverse, 'process_price'] = result_t.loc[
                                                                     first_index, 'process_price'] - bulk_price * (
                                                                             reverse - first_index)
                continue
            next_price = result_t.loc[reverse_index + 1, 'process_price']
            upper_price = result_t.loc[reverse_index - 1, 'process_price']
            begin_after_avg_price=(result_t.loc[reverse_index-1, 'process_price']+result_t.loc[reverse_index+1, 'process_price'])/2

            #针对当前行的价格比下面的要小，确定是否调整当前行的价格 或者下面一行的价格
            if reverse_index+1<size and middle_price<result_t.loc[reverse_index+1, 'process_price']:
                reverse_up_rate=abs(result_t.loc[reverse_index-1, 'process_price']-result_t.loc[reverse_index, 'process_price'])/result_t.loc[reverse_index, 'process_price']
                reverse_down_rate=abs(result_t.loc[reverse_index+1, 'process_price']-result_t.loc[reverse_index, 'process_price'])/result_t.loc[reverse_index, 'process_price']

                if result_t.loc[reverse_index, 'sale_num_0_7']>result_t.loc[reverse_index+1, 'sale_num_0_7'] \
                    or result_t.loc[reverse_index, 'count']>result_t.loc[reverse_index+1, 'count']:#此种针对下面一行的出货量少 ，需要调整下面的价格
                    if result_t.loc[reverse_index+1, 'price_0_7']>0 or result_t.loc[reverse_index+1, 'thisprice']>0:
                        next_bids_price = min(result_t.loc[reverse_index+1, 'process_price'],result_t.loc[reverse_index+1, 'process_price'] \
                                                if result_t.loc[reverse_index+1, 'price_0_7']<=0 else result_t.loc[reverse_index+1, 'price_0_7'])

                        next_bids_price = min(next_bids_price,next_bids_price if result_t.loc[reverse_index+1, 'thisprice']<=0 else result_t.loc[reverse_index+1, 'thisprice'])

                        if reverse_index+2<size:
                            if result_t.loc[reverse_index+1, 'process_price']>result_t.loc[reverse_index+2, 'process_price'] and result_t.loc[reverse_index,'reverse_cnt']<=5:#当前行不倒挂，则希望调低此行价格，继续保持不到挂
                                if next_bids_price>result_t.loc[reverse_index+2, 'process_price']:
                                    result_t.loc[reverse_index + 1, 'process_price']=next_bids_price
                                else:
                                    result_t.loc[reverse_index + 1, 'process_price'] = min(result_t.loc[reverse_index+2, 'process_price']+1,result_t.loc[reverse_index-1, 'process_price'])
                                result_t.loc[reverse_index + 1, 'reverse_cnt'] += 1
                                continue
                elif reverse_up_rate>0.05 and reverse_down_rate>0.05:
                    reverse_thisprice=result_t.loc[reverse_index-1, 'process_price']*0.95 if result_t.loc[reverse_index, 'thisprice']<=0 else result_t.loc[reverse_index, 'thisprice']
                    reverse_price=max(result_t.loc[reverse_index-1, 'process_price']*0.95,reverse_thisprice)
                    if result_t.loc[reverse_index, 'process_price']==reverse_price:
                        result_t.loc[reverse_index, 'process_price']=reverse_price+(result_t.loc[reverse_index-1, 'process_price']-reverse_price)*0.5
                    else:
                        result_t.loc[reverse_index, 'process_price']=reverse_price
                    result_t.loc[reverse_index, 'reverse_cnt'] += 1
                    continue

                    #1、middle_price!=begin_after_avg_price：防止重复更新
            if  result_t.loc[reverse_index-1, 'process_price']>=begin_after_avg_price and middle_price!=begin_after_avg_price and (~np.isnan(thisprice) and thisprice>0 and middle_price!=thisprice ) and middle_price!=next_price*1.03:
                diff_rate = begin_after_avg_price/thisprice-1
                if np.isnan(result_t.loc[reverse_index, 'thisprice']) or (diff_rate>-0.06 and diff_rate<=0.06):
                    result_t.loc[reverse_index, 'process_price']=begin_after_avg_price
                    # continue
                elif (reverse_index+1)<size and   result_t.loc[reverse_index+1, 'thisprice'] >0:
                    result_t.loc[reverse_index, 'process_price'] = min(begin_after_avg_price,result_t.loc[reverse_index+1, 'process_price']*1.01)
                else:
                    if result_t.loc[reverse_index-1, 'thisprice']>0:
                        result_t.loc[reverse_index, 'process_price'] = upper_price - 1
                    else:
                        if diff_rate>0:
                            result_t.loc[reverse_index, 'process_price'] = min(thisprice *1.06,upper_price - 1)
                        else:
                            result_t.loc[reverse_index, 'process_price'] = min(thisprice * 0.94, upper_price - 1)
                    # continue
                result_t.loc[reverse_index, 'reverse_cnt'] += 1
                continue


            else :
                diff_price=result_t.loc[reverse_index - 1, 'process_price']-middle_price
                diff_rate=diff_price/result_t.loc[reverse_index - 1, 'process_price']
                if diff_price>0 and diff_rate>0.01:
                    result_t.loc[reverse_index, 'process_price']=middle_price+diff_price*0.2
                else:
                    first_index=reverse_index-1
                    for first_index in range(reverse_index-1,0,-1):
                        if result_t.loc[first_index,'weight_cnt']==0 and result_t.loc[first_index, 'template_rank']!=result_t.loc[reverse_index, 'template_rank']:
                            break
                    for next_index in range(reverse_index + 1,size, 1):
                        if result_t.loc[next_index,'weight_cnt']==0 and result_t.loc[next_index, 'template_rank']!=result_t.loc[reverse_index, 'template_rank'] and result_t.loc[first_index, 'process_price'] > result_t.loc[next_index, 'process_price']:
                            break
                    # bulk_price=(result_t.loc[first_index, 'process_price'] - result_t.loc[next_index, 'process_price']) / (
                    #             next_index - first_index)

                    for reverse in range(first_index+1,next_index-1,1):
                        if result_t.loc[reverse, 'weight_cnt']>0:
                            if reverse>0 and (result_t.loc[reverse, 'process_price']<=result_t.loc[reverse-1, 'process_price'] or result_t.loc[reverse, 'template_rank']==result_t.loc[reverse-1, 'template_rank']):
                                continue
                                # pass
                            else:
                                if reverse>0 and result_t.loc[reverse, 'process_price']>result_t.loc[reverse-1, 'process_price'] and result_t.loc[reverse, 'template_rank']!=result_t.loc[reverse-1, 'template_rank']:
                                    if result_t.loc[reverse, 'sale_num_0_7']<=result_t.loc[reverse-1, 'sale_num_0_7']:
                                        result_t.loc[reverse, 'process_price']=result_t.loc[reverse-1, 'process_price'] -1
                                        result_t.loc[reverse, 'reverse_cnt'] += 1
                                        for next_equil_rank in range(reverse+1,next_index-1,1):
                                            if result_t.loc[reverse, 'template_rank'] == result_t.loc[next_equil_rank, 'template_rank']:
                                                result_t.loc[next_equil_rank, 'process_price'] = result_t.loc[
                                                                                             reverse - 1, 'process_price'] - 1
                                            else:
                                                break

                                    else:
                                        if reverse>1 and result_t.loc[reverse, 'process_price']<result_t.loc[reverse-2, 'process_price']:
                                            result_t.loc[reverse-1, 'process_price'] = result_t.loc[reverse , 'process_price'] + 1
                                            result_t.loc[reverse-1, 'reverse_cnt'] += 1
                                        elif reverse>1 and result_t.loc[reverse, 'process_price']>result_t.loc[reverse-2, 'process_price']:
                                            result_t.loc[reverse-1, 'process_price'] = result_t.loc[reverse - 2, 'process_price'] - 1
                                            result_t.loc[reverse, 'process_price'] = result_t.loc[reverse - 1, 'process_price'] - 1
                                            result_t.loc[reverse-1, 'reverse_cnt'] += 1
                                            result_t.loc[reverse, 'reverse_cnt'] += 1
                                            logger.info('特殊情况=sku={}'.format(result_t.loc[0,'product_sku_key']))
        else:
            result_t.loc[reverse_index, 'process_price'] = result_t.loc[reverse_index - 1, 'process_price']*0.99

        result_t.loc[reverse_index, 'reverse_cnt']+=1
        logger.info('iter={}'.format(index))
    return result_t


def inverse_level_process(input_df):
    t1 = time.time()
    result_t=input_df.sort_values(by=['template_rank', 'mean_rate'],ascending=[True, False])
    # result_t=result_t.loc[result_t.product_sku_key==187906]
    resDf = pd.DataFrame(columns=result_t.columns.tolist())
    grouped = result_t.groupby('product_sku_key')

    total_gp=grouped.ngroups
    iter=0
    if total_gp>5:
        with Pool(16) as executor:
            for number, result_t in zip(grouped,
                                      executor.map(inverse_process_fun,
                                                   grouped)):
                resDf = resDf.append(result_t.copy())
                iter += 1
                logger.info('total_gp ={},iter={} skuid={} is prime:'.format(total_gp,iter, number[0]))
        logger.info(' inverse_level_process2 end use time @{}'.format((time.time() - t1) / 60))
    else:
        for group in grouped:
            result_t = inverse_process_fun(group)
            resDf = resDf.append(result_t.copy())
    return resDf

def reverse_inverse_data(resDf):
    #倒挂修复前的数据进行备份对照
    resDf['iter_size_begin']=resDf['iter_size']
    resDf['iter_size_bi_begin']=resDf['iter_size_bi']
    resDf['iverse_begin']=resDf['iverse']
    resDf['iverse_bi_begin']=resDf['iverse_bi']

    #数据进行倒挂修复
    resDf=inverse_level_process(resDf)

    #倒挂处理完的数据进行重新倒挂处理
    resDf=inverse_rate_process(resDf)
    resDf.drop_duplicates(subset=['product_sku_key', 'product_level_key'], keep='first', inplace=True)

    check_conflict_file(FILE_DIR, 'sku2_price_reverse2_process3_data.pkl')
    save_pickle_data(FILE_DIR+'sku2_price_reverse2_process3_data.pkl', resDf)
    return resDf

"""
1、读取数据；
2、进行倒挂率测算；
3、进行等级倒挂率修复；
"""
def process3_level_inverse_fun():

    result = load_pickle_data(FILE_DIR+'sku2_price_property_reverse_calculation_process2_df.pkl')
    # result=result.loc[result.product_key.isin([32291])]
    resDf_begin=inverse_rate_process(result)


    # print('dsd')
    #数据进行倒挂修复
    resDf=reverse_inverse_data(resDf_begin)
    # resDf=load_pickle_data('/data/sunpengwei/tmp/sku2_price_reverse2_process3_data.pkl')
    return resDf


if __name__=='__main__':
    try:
        process3_level_inverse_fun()
    except Exception as e:
        logger.critical('level_reverse2 处理失败：@{}'.format(e))
        raise TypeError('level_reverse2 处理失败:') from e
        exit(1)
    logger.info('end!')


